gdk/wayland: Support the xdg-activation wayland protocol
authorCarlos Garnacho <carlosg@gnome.org>
Wed, 2 Dec 2020 16:22:41 +0000 (17:22 +0100)
committerCarlos Garnacho <carlosg@gnome.org>
Mon, 3 May 2021 15:20:50 +0000 (17:20 +0200)
This protocol implements the IPC necessary to focus application
windows across launcher/launchee. Add support for it.

gdk/wayland/gdkapplaunchcontext-wayland.c
gdk/wayland/gdkdevice-wayland.c
gdk/wayland/gdkdisplay-wayland.c
gdk/wayland/gdkdisplay-wayland.h
gdk/wayland/gdkprivate-wayland.h
gdk/wayland/gdksurface-wayland.c
gdk/wayland/meson.build
meson.build
subprojects/wayland-protocols.wrap

index ed9e69b0eb2f612c4669bf80a812f91a96897fdd..1e0b1b94c2c0a314d9567dc1574563cd4ee9b1fc 100644 (file)
 #include "gdkinternals.h"
 #include "gdkintl.h"
 
+typedef struct {
+  gchar *token;
+} AppLaunchData;
+
+static void
+token_done (gpointer                        data,
+            struct xdg_activation_token_v1 *provider,
+            const char                     *token)
+{
+  AppLaunchData *app_launch_data = data;
+
+  app_launch_data->token = g_strdup (token);
+}
+
+static const struct xdg_activation_token_v1_listener token_listener = {
+  token_done,
+};
+
 static char *
 gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
                                                       GAppInfo          *info,
@@ -39,7 +57,34 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context
 
   g_object_get (context, "display", &display, NULL);
 
-  if (display->gtk_shell_version >= 3)
+  if (display->xdg_activation)
+    {
+      struct xdg_activation_token_v1 *token;
+      GdkWaylandSeat *seat;
+      GdkSurface *focus_surface;
+      AppLaunchData app_launch_data = { 0 };
+
+      seat = GDK_WAYLAND_SEAT (gdk_display_get_default_seat (GDK_DISPLAY (display)));
+      focus_surface = gdk_wayland_device_get_focus (gdk_seat_get_keyboard (GDK_SEAT (seat)));
+      token = xdg_activation_v1_get_activation_token (display->xdg_activation);
+
+      xdg_activation_token_v1_add_listener (token,
+                                            &token_listener,
+                                            &app_launch_data);
+      xdg_activation_token_v1_set_serial (token,
+                                          _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
+                                          gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
+      xdg_activation_token_v1_set_surface (token,
+                                           gdk_wayland_surface_get_wl_surface (focus_surface));
+      xdg_activation_token_v1_commit (token);
+
+      while (app_launch_data.token == NULL)
+        wl_display_roundtrip (display->wl_display);
+
+      xdg_activation_token_v1_destroy (token);
+      id = app_launch_data.token;
+    }
+  else if (display->gtk_shell_version >= 3)
     {
       id = g_uuid_string_random ();
       gtk_shell1_notify_launch (display->gtk_shell, id);
index 564408dc0a88d8ed37bda6fa5a7f0aa8fe7fe308..3b9c1e02daca02fc075cb372d0a74f717db1a115 100644 (file)
@@ -656,7 +656,7 @@ device_emit_grab_crossing (GdkDevice       *device,
     }
 }
 
-static GdkSurface *
+GdkSurface *
 gdk_wayland_device_get_focus (GdkDevice *device)
 {
   GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
index e04f9e8987caf19798f905b06503d4dc56f452a3..41b2069a77a096fb9b5f925ce5a4a4951596fcdc 100644 (file)
@@ -90,6 +90,7 @@
 #define GTK_SHELL1_VERSION       4
 #define OUTPUT_VERSION_WITH_DONE 2
 #define NO_XDG_OUTPUT_DONE_SINCE_VERSION 3
+#define XDG_ACTIVATION_VERSION   1
 
 static void _gdk_wayland_display_load_cursor_theme (GdkWaylandDisplay *display_wayland);
 
@@ -493,6 +494,15 @@ gdk_registry_handle_global (void               *data,
         wl_registry_bind (display_wayland->wl_registry, id,
                           &zwp_idle_inhibit_manager_v1_interface, 1);
     }
+  else if (strcmp (interface, "xdg_activation_v1") == 0)
+    {
+      display_wayland->xdg_activation_version =
+        MIN (version, XDG_ACTIVATION_VERSION);
+      display_wayland->xdg_activation =
+        wl_registry_bind (display_wayland->wl_registry, id,
+                          &xdg_activation_v1_interface,
+                          display_wayland->xdg_activation_version);
+    }
 
   g_hash_table_insert (display_wayland->known_globals,
                        GUINT_TO_POINTER (id), g_strdup (interface));
@@ -857,7 +867,7 @@ gdk_wayland_display_notify_startup_complete (GdkDisplay  *display,
         return;
     }
 
-  if (display_wayland->gtk_shell)
+  if (!display_wayland->xdg_activation && display_wayland->gtk_shell)
     gtk_shell1_set_startup_id (display_wayland->gtk_shell, startup_id);
 
   g_free (free_this);
index 886210ef3c46fc7dc574689df70356c749b3e91e..4c27dd86a7bf56e64025586c08dd9146b84411d9 100644 (file)
@@ -37,6 +37,7 @@
 #include <gdk/wayland/xdg-output-unstable-v1-client-protocol.h>
 #include <gdk/wayland/idle-inhibit-unstable-v1-client-protocol.h>
 #include <gdk/wayland/primary-selection-unstable-v1-client-protocol.h>
+#include <gdk/wayland/xdg-activation-v1-client-protocol.h>
 
 #include <glib.h>
 #include <gdk/gdkkeys.h>
@@ -112,6 +113,7 @@ struct _GdkWaylandDisplay
   struct org_kde_kwin_server_decoration_manager *server_decoration_manager;
   struct zxdg_output_manager_v1 *xdg_output_manager;
   struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
+  struct xdg_activation_v1 *xdg_activation;
 
   GList *async_roundtrips;
 
@@ -139,6 +141,7 @@ struct _GdkWaylandDisplay
   int data_device_manager_version;
   int gtk_shell_version;
   int xdg_output_manager_version;
+  int xdg_activation_version;
 
   uint32_t server_decoration_mode;
 
index eadacffbb970887653e962ff7ee27b5832ce791f..908288e877faaeb59971d5958d5eaca5be95e92d 100644 (file)
@@ -140,6 +140,8 @@ uint32_t _gdk_wayland_seat_get_implicit_grab_serial(GdkSeat  *seat,
                                                     GdkEvent *event);
 uint32_t _gdk_wayland_seat_get_last_implicit_grab_serial (GdkWaylandSeat     *seat,
                                                           GdkEventSequence **sequence);
+GdkSurface * gdk_wayland_device_get_focus (GdkDevice *device);
+
 struct wl_data_device * gdk_wayland_device_get_data_device (GdkDevice *gdk_device);
 void gdk_wayland_device_set_selection (GdkDevice             *gdk_device,
                                        struct wl_data_source *source);
index ba4d78bac2b5e75b077aada5d6730ec9928bd3a0..66a8001bcdb6e48bb66530fe131efb9cbffbe2b8 100644 (file)
@@ -3464,10 +3464,20 @@ gdk_wayland_surface_focus (GdkSurface *surface,
       GdkWaylandDisplay *display_wayland =
         GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
 
-      if (display_wayland->gtk_shell_version >= 3)
+      if (display_wayland->startup_notification_id)
         {
-          gtk_surface1_request_focus (impl->display_server.gtk_surface,
-                                      display_wayland->startup_notification_id);
+          if (display_wayland->xdg_activation)
+            {
+              xdg_activation_v1_activate (display_wayland->xdg_activation,
+                                          display_wayland->startup_notification_id,
+                                          impl->display_server.wl_surface);
+            }
+          else if (display_wayland->gtk_shell_version >= 3)
+            {
+              gtk_surface1_request_focus (impl->display_server.gtk_surface,
+                                          display_wayland->startup_notification_id);
+            }
+
           g_clear_pointer (&display_wayland->startup_notification_id, g_free);
         }
     }
index 833945f6662ad29ee342b874d96cb2fd59cffdcc..28a00a959b6d252b1078c7bfd1bf2c1146346209 100644 (file)
@@ -56,6 +56,7 @@ proto_sources = [
   ['server-decoration', 'private' ],
   ['xdg-output', 'unstable', 'v1', ],
   ['idle-inhibit', 'unstable', 'v1', ],
+  ['xdg-activation', 'staging', 'v1', ],
 ]
 
 gdk_wayland_gen_headers = []
@@ -67,6 +68,10 @@ foreach p: proto_sources
   if proto_stability == 'stable'
     output_base = proto_name
     input = files(join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base)))
+  elif proto_stability == 'staging'
+    proto_version = p.get(2)
+    output_base = '@0@-@1@'.format(proto_name, proto_version)
+    input = join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base))
   elif proto_stability == 'private'
     output_base = proto_name
     input = files('protocol/@0@.xml'.format(proto_name))
index 7aee079d23891796226de6e7905f4f2ca24411ca..d8660cbe85a09e5bc6c228ea74886105b5312a4a 100644 (file)
@@ -16,7 +16,7 @@ fribidi_req        = '>= 0.19.7'
 cairo_req          = '>= 1.14.0'
 gdk_pixbuf_req     = '>= 2.30.0'
 introspection_req  = '>= 1.39.0'
-wayland_proto_req  = '>= 1.20'
+wayland_proto_req  = '>= 1.21'
 wayland_req        = '>= 1.14.91'
 graphene_req       = '>= 1.9.1'
 epoxy_req          = '>= 1.4'
index ba60db715dfc9ff5d97e94d93c63bf22d4d9fe01..065651db6372499631c3c8dc75e7e0c30d6976a6 100644 (file)
@@ -1,5 +1,5 @@
 [wrap-git]
 directory=wayland-protocols
-url=https://gitlab.freedesktop.org/jadahl/wayland-protocols.git
-revision=wip/meson-meson-0.53
+url=https://gitlab.freedesktop.org/wayland/wayland-protocols.git
+revision=main
 depth=1